using System;
using System.Collections.Generic;
using System.Linq;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityGameFramework.Runtime;

public class Block : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{    
    float zDistance;
    Vector2 offset;
    Vector2 dragStartPos;

    BlockLayer layer;
    TestBlockMap map;
    int length = 1;
    int startPos = 0;
    SpriteRenderer sr;
    BoxCollider2D bc;
    Rigidbody2D rb;

    bool isDrag = false;
    bool isDown = false;
    float speed;
    float gravity = -9.8f;
    float destination;
    float maxLeftEdge;
    float maxRightEdge;

    public bool IsEmpty => sr.color.a == 0;
    public BlockLayer OwnerLayer { get { return layer; } set { layer = value; } }
    public int StartPos { get { return startPos; } set{ startPos = value; } }
    public int Length => length;
    public float LeftEdge => transform.position.x - 0.5f*sr.size.x;
    public float RightEdge => transform.position.x + 0.5f*sr.size.x;
    public Vector2 Size => sr.bounds.size;

    private void Awake()
    {
        sr = GetComponent<SpriteRenderer>();        
        bc = GetComponent<BoxCollider2D>();        
    }

    public void Init(TestBlockMap map, BlockLayer layer,int startPos,int length,bool isEmpty)
    {
        this.layer = layer;                        
        this.length = length;        
        this.map = map;
        this.startPos = startPos;
        sr.size = new Vector2(length, 1);
        bc.size = sr.size;
        float f = length * 0.1f;
        sr.color = new Color(f, f, f, isEmpty ? 0 : 1);
    }

    private void Update()
    {
        if (isDown)
        {
            speed +=  gravity * Time.deltaTime;
            Vector2 pos = transform.position;
            pos.y += speed * Time.deltaTime;            
            if (Mathf.Approximately(destination,pos.y) || pos.y < destination)
            {
                Debug.Log("End Down");
                pos.y = destination;
                isDown = false;
                map.DownNum--;
            }
            transform.position = pos;
        }
    }
    
    public void SetToEmpty()
    {
        sr.color = new Color(0, 0, 0, 0);
        sr.size = new(1, 1);
    }

    public void MoveDown(float destination)
    {
        isDown = true;
        map.DownNum++;
        speed = 0;
        this.destination = destination;
    }

    public void OnBeginDrag(PointerEventData eventData)
    {
        if (map.DownNum != 0 || IsEmpty)
        {
            eventData.pointerDrag = null;
            return;
        }

        map.HasBlockOnDrag = true;

        sr.sortingOrder++;
        zDistance = transform.position.z - Camera.main.transform.position.z;        
        Vector2 worldPos = Camera.main.ScreenToWorldPoint(new(eventData.position.x, eventData.position.y, zDistance));
        dragStartPos = transform.position;
        offset = (Vector2)transform.position - worldPos;

        maxLeftEdge = GetMaxLeftEdge();
        maxRightEdge = GetMaxRightEdge();
    }

    public void OnDrag(PointerEventData eventData)
    {
        Vector3 worldPos = Camera.main.ScreenToWorldPoint(new(eventData.position.x,eventData.position.y,zDistance));
        var pos =transform.position;
        pos.x = worldPos.x + offset.x;
        pos.x = Mathf.Clamp(pos.x, maxLeftEdge+sr.size.x*0.5f, maxRightEdge-sr.size.x * 0.5f);
        transform.position = pos;
    }

    public void OnEndDrag(PointerEventData eventData)
    {
        sr.sortingOrder--;
        map.HasBlockOnDrag = false;
        float moveDis = transform.position.x - dragStartPos.x;
        int addIdx = (int)moveDis;
        if (Math.Abs(addIdx)>=1f)
        {
            int curIdx = transform.GetSiblingIndex();            
            int targetIdx = Math.Clamp(curIdx + addIdx, 0, OwnerLayer.transform.childCount - 1);
            OwnerLayer.ResetBlock(curIdx, targetIdx);                  
            map.AddLayer();
        }
        else
        {
            transform.position = dragStartPos;
        }        
    }

    float GetMaxLeftEdge()
    {
        Block minNearBlock=null;
        for(int i=0;i<transform.GetSiblingIndex();i++)
        {
            var block = OwnerLayer.Blocks[i];
            if (block.IsEmpty)
                continue;
            if (minNearBlock == null)
                minNearBlock = block;
            else if (minNearBlock.StartPos < block.StartPos)
            {
                minNearBlock = block;
            }
        }

        if (minNearBlock != null)
            return minNearBlock.RightEdge;
        else
            return map.LeftEdge;
    }

    float GetMaxRightEdge()
    {
        Block minNearBlock = null;
        for (int i = OwnerLayer.Blocks.Count-1; i >transform.GetSiblingIndex(); i--)
        {
            var block = OwnerLayer.Blocks[i];
            if (block.IsEmpty)
                continue;
            if (minNearBlock == null)
                minNearBlock = block;
            else if (minNearBlock.StartPos > block.StartPos)
            {
                minNearBlock = block;
            }
        }
        if (minNearBlock != null)
            return minNearBlock.LeftEdge;
        else
            return map.RightEdge;
    }
}
